import type { Ref } from 'vue'
import { nextTick } from 'vue'
import { BrowserJsPlumbInstance, uuid } from '@jsplumb/browser-ui'
import type { ClipboardNode, DataFlow } from '@/model/data-flow/data-flow'
import { operatorTypeInfoMapping } from '@/views/main/data-flow/design/index'
import { px2Number } from '@/utils/common-util'

export function addNode(
  zoom: number,
  offset: { left: number; top: number },
  event: MouseEvent,
  operationSpaceRef: Ref<any>,
  jsplumbInstance: Ref<BrowserJsPlumbInstance | undefined>,
  dataFlowState: DataFlow
) {
  const id = uuid()
  const functionType = (event.target as HTMLElement).getAttribute('data-type')!
  const name = operatorTypeInfoMapping.get(functionType!)?.name!
  dataFlowState.addNode(id, name, functionType)
  nextTick().then(() => {
    const element = document.getElementById(id)!
    const rect = operationSpaceRef.value.getBoundingClientRect()
    element.style.left = (event.clientX - rect.left - offset.left) / zoom + 'px'
    element.style.top = (event.clientY - rect.top - offset.top) / zoom + 'px'
    jsplumbInstance.value?.addEndpoint(
      element,
      {
        source: true,
        target: true,
        maxConnections: 100
      },
      {
        uuid: id
      }
    )
  })
}

export function deleteNode(
  operationSpaceRef: Ref<any>,
  jsplumbInstance: Ref<BrowserJsPlumbInstance | undefined>,
  dataFlowState: DataFlow
) {
  dataFlowState.selectedNodes.forEach((id) => {
    const element = jsplumbInstance.value?.getManagedElement(id)!
    jsplumbInstance.value?.deleteConnectionsForElement(element)
    jsplumbInstance.value?.deleteEndpoint(id)
    dataFlowState.nodes.delete(id)
    dataFlowState.connectors.delete(id)
  })
  dataFlowState.selectedNodes.clear()
}

export function copyNode(
  jsplumbInstance: Ref<BrowserJsPlumbInstance | undefined>,
  dataFlowState: DataFlow
) {
  if (dataFlowState.selectedNodes.size <= 0) {
    return
  }
  let minLeft = Number.MAX_VALUE
  let minTop = Number.MAX_VALUE
  const array: ClipboardNode[] = []
  for (const id of dataFlowState.selectedNodes) {
    const dataFlowNode = dataFlowState.nodes.get(id)
    if (!dataFlowNode) {
      continue
    }
    const element = jsplumbInstance.value?.getEndpoint(id).element
    minLeft = Math.min(px2Number(element.style.left), minLeft)
    minTop = Math.min(px2Number(element.style.top), minTop)
    array.push({
      id: dataFlowNode.id,
      name: dataFlowNode.name,
      type: dataFlowNode.type,
      info: Object.assign(dataFlowNode.info),
      position: {
        left: px2Number(element.style.left),
        top: px2Number(element.style.top)
      }
    })
  }
  dataFlowState.clearClipboard()
  for (const node of array) {
    node.position.left = node.position.left - minLeft
    node.position.top = node.position.top - minTop
    dataFlowState.clipboard.nodes.add(node)
  }
  dataFlowState.clipboard.position.left = minLeft
  dataFlowState.clipboard.position.top = minTop
}

export function pasteNode(
  jsplumbInstance: Ref<BrowserJsPlumbInstance | undefined>,
  operationSpaceRef: Ref<any>,
  dataFlowState: DataFlow,
  zoom: number,
  event?: PointerEvent
) {
  if (dataFlowState.clipboard.nodes.size <= 0) {
    return
  }
  const ids: string[] = []
  const rect = operationSpaceRef.value.getBoundingClientRect()
  let baseLeft = dataFlowState.clipboard.position.left + 20 * zoom
  let baseTop = dataFlowState.clipboard.position.top + 20 * zoom
  if (event) {
    baseLeft = event.clientX - rect.left
    baseTop = event.clientY - rect.top
  }
  for (const clipboardNode of dataFlowState.clipboard.nodes) {
    const id = uuid()
    const functionType = clipboardNode.type
    const name = clipboardNode.name
    dataFlowState.addNode(id, name, functionType)
    nextTick().then(() => {
      const element = document.getElementById(id)!
      element.style.left = (baseLeft + clipboardNode.position.left) / zoom + 'px'
      element.style.top = (baseTop + clipboardNode.position.top) / zoom + 'px'
      jsplumbInstance.value?.addEndpoint(
        element,
        {
          source: true,
          target: true,
          maxConnections: 100
        },
        {
          uuid: id
        }
      )
      ids.push(id)
    })
  }
  nextTick().then(() => {
    dataFlowState.setSelectedNode(ids)
  })
}
